package dao

import (
	"encoding/json"
	"sync"
	"time"
	"user_srv/basic/config"
	"user_srv/handler/model"
)

// WSConnection WebSocket连接管理结构体
// 用于维护用户与WebSocket连接的映射关系
// UserId: 用户ID
// Conn: WebSocket连接（使用interface{}类型，避免包依赖问题）
type WSConnection struct {
	UserId int64
	Conn   interface{} // 这里应该是websocket.Conn类型，但由于包依赖问题使用interface{}
}

// ChatService 聊天服务
// 负责处理聊天相关的业务逻辑
// - connections: WebSocket连接池，维护在线用户的连接映射
// - mutex: 读写锁，保证并发安全
type ChatService struct {
	// WebSocket连接池，map[用户ID]连接对象
	connections map[int64]*WSConnection
	mutex       sync.RWMutex
}

// 全局聊天服务实例
var chatServiceInstance *ChatService
var once sync.Once

// 获取聊天服务单例
func GetChatService() *ChatService {
	once.Do(func() {
		chatServiceInstance = &ChatService{
			connections: make(map[int64]*WSConnection),
		}
	})
	return chatServiceInstance
}

// AddConnection 添加WebSocket连接
// 功能：将用户的WebSocket连接加入到连接池
// 应用场景：用户登录或重新连接时调用
// 参数：
//   - userId: 用户ID
//   - conn: WebSocket连接对象
func (c *ChatService) AddConnection(userId int64, conn interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.connections[userId] = &WSConnection{
		UserId: userId,
		Conn:   conn,
	}
}

// RemoveConnection 移除WebSocket连接
// 功能：从连接池中移除用户的WebSocket连接
// 应用场景：用户离线或断开连接时调用
func (c *ChatService) RemoveConnection(userId int64) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	delete(c.connections, userId)
}

// SendWSMessage 发送WebSocket消息
// 功能：通过WebSocket向在线用户发送实时消息
// 如果用户不在线，返回 ErrUserNotOnline 错误
// 参数：
//   - userId: 接收消息的用户ID
//   - message: 要发送的消息对象
func (c *ChatService) SendWSMessage(userId int64, message interface{}) error {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	_, exists := c.connections[userId]
	if !exists {
		return ErrUserNotOnline
	}

	// 这里需要根据实际的WebSocket实现来发送消息
	// 由于包依赖问题，这里使用interface{}，实际使用时需要类型断言
	_, err := json.Marshal(message)
	if err != nil {
		return err
	}

	// 实际发送逻辑需要在API Gateway层实现
	// 这里只是标记消息需要发送
	return nil
}

// SendMessage 发送聊天消息
// 功能：在匹配关系中发送消息，并实时推送给接收方
// 处理流程：
//  1. 验证匹配关系
//  2. 确定接收者ID
//  3. 创建并保存消息记录到数据库
//  4. 通过WebSocket实时推送给接收方（如果在线）
//  5. 发送推送通知给离线用户
//
// 参数：
//   - senderId: 发送者ID
//   - matchId: 匹配关系ID
//   - content: 消息内容
//   - messageType: 消息类型（1=文本，2=图片，3=语音）
//
// 返回值：ChatMessageInfo 消息信息对象
func (c *ChatService) SendMessage(senderId, matchId int64, content string, messageType int8) (*ChatMessageInfo, error) {
	// 1. 验证匹配关系
	match, err := c.validateMatch(senderId, matchId)
	if err != nil {
		return nil, err
	}

	// 2. 确定接收者ID
	receiverId := match.GetMatchedUserId(senderId)

	// 3. 创建消息记录
	message := model.XqChatMessages{
		MatchId:   matchId,
		SenderId:  senderId,
		Content:   content,
		MsgType:   messageType,
		IsRead:    0,
		CreatedAt: time.Now(),
	}

	// 4. 保存消息
	if err := message.Create(); err != nil {
		return nil, err
	}

	// 5. 构建消息信息
	messageInfo := &ChatMessageInfo{
		Id:        message.Id,
		MatchId:   message.MatchId,
		SenderId:  message.SenderId,
		Content:   message.Content,
		MsgType:   message.MsgType,
		IsRead:    message.IsRead,
		CreatedAt: message.CreatedAt.Unix(),
	}

	// 6. 通过WebSocket实时推送消息给接收者
	go c.pushMessageToReceiver(receiverId, messageInfo)

	// 7. 发送消息通知（用于离线用户）
	var notificationService NotificationService
	err = notificationService.SendMessageNotification(senderId, receiverId, matchId, content)
	if err != nil {
		// 通知发送失败不影响消息发送
		// log.Printf("发送消息通知失败: %v", err)
	}

	return messageInfo, nil
}

// pushMessageToReceiver 推送消息给接收者
// 功能：通过WebSocket向接收者推送新消息
// 如果用户不在线，消息已保存到数据库，用户上线后可以获取
// 参数：
//   - receiverId: 接收者用户ID
//   - messageInfo: 消息信息对象
func (c *ChatService) pushMessageToReceiver(receiverId int64, messageInfo *ChatMessageInfo) {
	// 构建WebSocket消息格式
	wsMessage := map[string]interface{}{
		"type": "new_message",
		"data": messageInfo,
	}

	// 尝试通过WebSocket发送
	if err := c.SendWSMessage(receiverId, wsMessage); err != nil {
		// 如果用户不在线，消息已保存到数据库，用户上线后可以获取
		// log.Printf("推送消息失败，用户可能离线: %v", err)
	}
}

// GetChatMessages 获取聊天消息列表
// 功能：获取指定匹配关系的聊天消息历史记录
// 处理逻辑：
//  1. 验证匹配关系（确保用户有权限访问）
//  2. 按时间倒序查询消息（最新的在前）
//  3. 自动标记消息为已读（只标记对方发送的消息）
//
// 参数：
//   - userId: 当前用户ID
//   - matchId: 匹配关系ID
//   - page: 页码（从1开始）
//   - pageSize: 每页数量（默认20，最大100）
//
// 返回值：
//   - []ChatMessageInfo: 消息列表
//   - int32: 总记录数
func (c *ChatService) GetChatMessages(userId, matchId int64, page, pageSize int32) ([]ChatMessageInfo, int32, error) {
	// 1. 验证匹配关系
	_, err := c.validateMatch(userId, matchId)
	if err != nil {
		return nil, 0, err
	}

	// 2. 设置分页参数
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}

	offset := (page - 1) * pageSize

	// 3. 获取消息列表
	var messageModel model.XqChatMessages
	messages, err := messageModel.ListByMatchId(matchId, int(pageSize), int(offset))
	if err != nil {
		return nil, 0, err
	}

	// 4. 获取总数
	var total int64
	err = config.DB.Model(&model.XqChatMessages{}).Where("match_id = ?", matchId).Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 5. 转换为响应格式
	var messageInfos []ChatMessageInfo
	for _, message := range messages {
		info := ChatMessageInfo{
			Id:        message.Id,
			MatchId:   message.MatchId,
			SenderId:  message.SenderId,
			Content:   message.Content,
			MsgType:   message.MsgType,
			IsRead:    message.IsRead,
			CreatedAt: message.CreatedAt.Unix(),
		}
		messageInfos = append(messageInfos, info)
	}

	// 6. 标记消息为已读（只标记对方发送的消息）
	go c.markMessagesAsRead(matchId, userId)

	return messageInfos, int32(total), nil
}

// MarkMessagesAsRead 标记消息为已读
// 功能：将某个匹配关系中的未读消息标记为已读
// 应用场景：用户打开聊天界面时自动调用
// 参数：
//   - userId: 用户ID
//   - matchId: 匹配关系ID
func (c *ChatService) MarkMessagesAsRead(userId, matchId int64) error {
	// 验证匹配关系
	_, err := c.validateMatch(userId, matchId)
	if err != nil {
		return err
	}

	return c.markMessagesAsRead(matchId, userId)
}

// GetUnreadMessageCount 获取未读消息数量
// 功能：统计用户在所有匹配关系中的未读消息总数
// 应用场景：在界面右上角显示红点通知
// 统计逻辑：
//   - 获取用户的所有匹配关系
//   - 统计每个匹配中对方发送的未读消息数量
//   - 汇总所有未读消息
//
// 参数：
//   - userId: 用户ID
//
// 返回值：未读消息总数
func (c *ChatService) GetUnreadMessageCount(userId int64) (int64, error) {
	// 获取用户的所有匹配
	var matches []model.XqUserMatches
	err := config.DB.Where("(user_id1 = ? OR user_id2 = ?) AND is_active = 1", userId, userId).Find(&matches).Error
	if err != nil {
		return 0, err
	}

	var totalUnread int64
	for _, match := range matches {
		// 统计该匹配中对方发送的未读消息
		var count int64
		err = config.DB.Model(&model.XqChatMessages{}).
			Where("match_id = ? AND sender_id != ? AND is_read = 0", match.Id, userId).
			Count(&count).Error
		if err != nil {
			continue
		}
		totalUnread += count
	}

	return totalUnread, nil
}

// DeleteMessage 删除消息
// 功能：删除用户自己发送的消息
// 权限控制：只能删除自己发送的消息
// 参数：
//   - userId: 用户ID（用于权限验证）
//   - messageId: 消息ID
func (c *ChatService) DeleteMessage(userId, messageId int64) error {
	// 1. 获取消息信息
	var message model.XqChatMessages
	err := config.DB.Where("id = ?", messageId).First(&message).Error
	if err != nil {
		return ErrMessageNotFound
	}

	// 2. 验证权限（只能删除自己发送的消息）
	if message.SenderId != userId {
		return ErrNoPermission
	}

	// 3. 删除消息
	return config.DB.Delete(&message).Error
}

// validateMatch 验证匹配关系
// 功能：验证用户是否有权限访问某个匹配关系
// 验证逻辑：
//  1. 检查匹配记录是否存在
//  2. 验证用户是否参与了该匹配（userId1 或 userId2）
//
// 参数：
//   - userId: 用户ID
//   - matchId: 匹配关系ID
//
// 返回值：匹配记录对象
func (c *ChatService) validateMatch(userId, matchId int64) (*model.XqUserMatches, error) {
	var matchModel model.XqUserMatches
	match, err := matchModel.GetByMatchId(matchId)
	if err != nil {
		return nil, ErrMatchNotFound
	}

	// 验证用户是否参与了这个匹配
	if match.UserId1 != userId && match.UserId2 != userId {
		return nil, ErrMatchNotFound
	}

	return match, nil
}

// 标记消息为已读（内部方法）
func (c *ChatService) markMessagesAsRead(matchId, userId int64) error {
	var messageModel model.XqChatMessages
	return messageModel.MarkAsRead(matchId, userId)
}

// ChatMessageInfo 聊天消息信息结构体
// 用于返回聊天消息的详细信息
// - Id: 消息ID
// - MatchId: 匹配关系ID
// - SenderId: 发送者ID
// - Content: 消息内容
// - MsgType: 消息类型（1=文本，2=图片，3=语音）
// - IsRead: 是否已读（0=未读，1=已读）
// - CreatedAt: 创建时间（Unix时间戳）
type ChatMessageInfo struct {
	Id        int64  `json:"id"`
	MatchId   int64  `json:"match_id"`
	SenderId  int64  `json:"sender_id"`
	Content   string `json:"content"`
	MsgType   int8   `json:"msg_type"` // 1:文本 2:图片 3:语音
	IsRead    int8   `json:"is_read"`
	CreatedAt int64  `json:"created_at"`
}
